﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.ETL.Infrastructure
{
    public class PropertyUtil
    {
        #region get path-type
        /// <summary>
        /// 获取属性路径列表
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static void GetPropertyPathList(Type type, string prefix, out List<string> paths, out List<Type> types)
        {
            paths = new List<string>();
            types = new List<Type>();

            PropertyInfo[] properties = type.GetProperties();
            for (int index = 0; index < properties.Length; index++)
            {
                PropertyInfo property = properties[index];
                string fullPath = GetFullPath(prefix, property.Name);
                if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
                {
                    _GetPropertyPathList(property.PropertyType, fullPath, ref paths, ref types);
                }
                else
                {
                    paths.Add(fullPath);
                    types.Add(property.PropertyType);
                }
            }

            FieldInfo[] fields = type.GetFields();
            for (int index = 0; index < fields.Length; index++)
            {
                FieldInfo field = fields[index];
                string fullPath = GetFullPath(prefix, field.Name);
                if (field.FieldType.IsClass && field.FieldType != typeof(string))
                {
                    _GetFieldPathList(field.FieldType, fullPath, ref paths, ref types);
                }
                else
                {
                    paths.Add(fullPath);
                    types.Add(field.FieldType);
                }
            }
        }

        private static void _GetPropertyPathList(Type type, string prefix, ref List<string> paths, ref List<Type> types)
        {
            PropertyInfo[] properties = type.GetProperties();
            for (int index = 0; index < properties.Length; index++)
            {
                PropertyInfo property = properties[index];

                string fullPath = GetFullPath(prefix, property.Name);

                if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
                {
                    _GetPropertyPathList(property.PropertyType, fullPath, ref paths, ref types);
                }
                else
                {
                    paths.Add(fullPath);
                    types.Add(property.PropertyType);
                }
            }
        }

        private static void _GetFieldPathList(Type fieldType, string prefix, ref List<string> paths, ref List<Type> types)
        {
            FieldInfo[] fields = fieldType.GetFields();
            for (int index = 0; index < fields.Length; index++)
            {
                FieldInfo field = fields[index];

                string fullPath = GetFullPath(prefix, field.Name);

                if (field.FieldType.IsClass && field.FieldType != typeof(string))
                {
                    _GetFieldPathList(field.FieldType, fullPath, ref paths, ref types);
                }
                else
                {
                    paths.Add(fullPath);
                    types.Add(field.FieldType);
                }
            }
        }
        #endregion

        #region get path-value
        /// <summary>
        /// 获取属性路径-value列表
        /// </summary>
        /// <param name="type"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static void GetPropertyPathValueList(Type type,  object instance, string prefix, out List<string> paths, out List<object> values)
        {
            paths = new List<string>();
            values = new List<object>();

            PropertyInfo[] properties = type.GetProperties();
            for (int index = 0; index < properties.Length; index++)
            {
                PropertyInfo property = properties[index];
                string fullPath = GetFullPath(prefix, property.Name);
                if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
                {
                    _GetPropertyPathValueList(property.PropertyType, instance, fullPath, ref paths, ref values);
                }
                else
                {
                    paths.Add(fullPath);
                    values.Add(property.GetValue(instance));
                }
            }

            FieldInfo[] fields = type.GetFields();
            for (int index = 0; index < fields.Length; index++)
            {
                FieldInfo field = fields[index];
                string fullPath = GetFullPath(prefix, field.Name);
                if (field.FieldType.IsClass && field.FieldType != typeof(string))
                {
                    _GetPropertyPathValueList(field.FieldType, instance, fullPath, ref paths, ref values);
                }
                else
                {
                    paths.Add(fullPath);
                    values.Add(field.GetValue(instance));
                }
            }
        }

        private static void _GetPropertyPathValueList(Type type, object instance, string prefix, ref List<string> paths, ref List<object> values)
        {
            PropertyInfo[] properties = type.GetProperties();
            for (int index = 0; index < properties.Length; index++)
            {
                PropertyInfo property = properties[index];

                string fullPath = GetFullPath(prefix, property.Name);

                if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
                {
                    object proValue = property.GetValue(instance);
                    _GetPropertyPathValueList(property.PropertyType, proValue, fullPath, ref paths, ref values);
                }
                else
                {
                    paths.Add(fullPath);
                    values.Add(property.GetValue(instance));
                }
            }
        }

        private static void _GetFieldPathValueList(Type fieldType, object instance, string prefix, ref List<string> paths, ref List<object> values)
        {
            FieldInfo[] fields = fieldType.GetFields();
            for (int index = 0; index < fields.Length; index++)
            {
                FieldInfo field = fields[index];

                string fullPath = GetFullPath(prefix, field.Name);

                if (field.FieldType.IsClass && field.FieldType != typeof(string))
                {
                    object fdValue = field.GetValue(instance);
                    _GetFieldPathValueList(field.FieldType, fdValue, fullPath, ref paths, ref values);
                }
                else
                {
                    paths.Add(fullPath);
                    values.Add(field.GetValue(instance));
                }
            }
        }
        #endregion

        private static string GetFullPath(string prefix, string name)
        {
            string resolvedName = name;
            if (resolvedName.StartsWith("_"))
            {
                resolvedName = resolvedName.Replace("_", string.Empty);
            }
            if (name.Contains("."))
            {
                resolvedName = resolvedName.Replace(".", string.Empty);
            }

            if (!string.IsNullOrEmpty(prefix))
            {
                return string.Format("{0}.{1}", prefix, resolvedName);
            }
            return resolvedName;
        }
    }
}
